# -*- mode: org; fill-column: 80; -*-
#+TITLE: GNU Guix Patch Guide
#+AUTHOR: Zelphir Kaltstahl
#+EMAIL: zelphirkaltstahl@posteo.de
#+STARTUP: content indent align inlineimages hideblocks entitiesplain nologdone nologreschedule nologredeadline nologrefile
#+TODO: TODO WIP DEPRECATED | DONE
#+DATE: [2021-09-12 Sun]
#+KEYWORDS: Guix GNU packaging guide
#+LANGUAGE: English
#+PRIORITIES: A E E
#+EXCLUDE_TAGS: noexport
#+OPTIONS: ^:{}
#+OPTIONS: H:10
#+OPTIONS: toc:2
#+OPTIONS: tags:nil
#+OPTIONS: tasks:t
#+OPTIONS: H:6
#+OPTIONS: p:nil
#+OPTIONS: pri:nil
#+OPTIONS: prop:nil
#+OPTIONS: todo:t
#+OPTIONS: stat:nil
#+OPTIONS: |:t
#+OPTIONS: inline:nil
#+OPTIONS: date:t

* Introduction
:PROPERTIES:
:CUSTOM_ID: introduction
:END:

This guide aims to summarize things to look out for, when trying to get a
package onto the official GNU Guix package manager repository. It contains
important points from the following documentation pages and pages these pages
link to:

+ [[https://guix.gnu.org/cookbook/en/html_node/Direct-checkout-hacking.html][Direct Checkout Hacking]]
+ [[https://guix.gnu.org/manual/en/html_node/Packaging-Guidelines.html][Packaging Guidelines]]
+ [[https://guix.gnu.org/manual/en/html_node/Submitting-Patches.html][Submitting Patches]]

* Basic information
:PROPERTIES:
:CUSTOM_ID: basic-information
:END:

+ GNU Guix packages are defined in the code of GNU Guix itself. Many packages
  are defined in files like [[https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/packages/guile-xyz.scm][guile-xyz.scm]] or [[https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/packages/guile.scm][guile.scm]]. Therein one can find
  examples of how to define a package.

+ Changes to the GNU Guix repository can be send to the ~guix-patches@gnu.org~
  mailing list as patches.

+ Patches need to conform to certain guidelines, to be accepted.

* Add package to GNU Guix
:PROPERTIES:
:CUSTOM_ID: add-package-to-gnu-guix
:END:

Adding a package to GNU Guix consists of 2 steps:

1. Clone the repository:

   #+begin_src shell
   git clone https://git.savannah.gnu.org/git/guix.git
   #+end_src

2. Edit ~gnu/packages/guile-xyz.scm~ to add your package
   definition. =gnu/packages/guile-xyz.scm= should be in the
   root directory of the GNU Guix source tree.

For an example package definition see
[[file:example-package-definition.scm][example-package-definition.scm]]. Furthermore the source code of GNU Guix also
contains some snippets at =etc/snippets/scheme-mode/=, which might be of use for
=yasnippet= users. Some of them are used for creating commit messages, which fit
the GNU Guix maintainers' wishes.

#+INCLUDE: "parts/calculate-hashes.org" :minlevel 2

* Testing the package definition
:PROPERTIES:
:CUSTOM_ID: testing-the-package-definition
:END:

Once the package definition is written into the GNU Guix sources, there is a
testing facility one should use (official reference: [[https://guix.gnu.org/manual/en/html_node/Running-Guix-Before-It-Is-Installed.html][Running Guix Before It Is
Installed]]), before submitting patches for integration of the package into the
official GNU Guix repository. This is to make sure, that the package will work
for other people, who try to install it using the GNU Guix package manager.

Instead of testing by installing a modified GNU Guix on a system to test the
distribution, there is a way of testing without installing it, by using a script
~pre-inst-env~. This script is not contained directly within the GNU Guix
sources. It needs to be generated.

In the following some commands will be prefixed with ~guix environment guix
--~. Instead of prefixing each command, which is supposed to run inside this GNU
Guix environment, it might be simpler to enter such an environment once, for
example by running ~guix environment guix~ and then run commands inside the
environment, without leaving it. This guide chooses to invoke ~guix environment
guix~ for each command, where the command should be run inside the guix
environment, to make it explicitly clear, when that is the case and to keep the
commands stand-alone copy-paste-able.

** Generate pre-installation environment script
:PROPERTIES:
:CUSTOM_ID: test-package-generate-pre-installation-environment-script
:END:

There is a pre-installation environment script, which helps with testing the
package, but it needs to be generated at first. The script has some
prerequisites itself. It will not work out of the box and needs to be run inside
a specific GNU Guix environment, which in turn means, that you will need GNU
Guix installed on the system to test on GNU Guix packages using the GNU Guix
source tree[fn:snake-tail].

The next mandatory step is to install GNU Guix on your system. Refer to [[https://guix.gnu.org/manual/en/html_node/Binary-Installation.html][Binary
Installation]].

To generate it the =pre-int-env= script, one needs to run the following commands
in the root directory of GNU Guix:

#+begin_src shell
guix shell --development guix -- ./bootstrap
guix shell --development guix -- ./configure --localstatedir=/var
#+end_src

~guix environment guix --~ makes sure to be in an environment, that has no
environment variables set from the current shell and installs the dependencies
of GNU Guix, which are required for development. This part of the command will
drop into a shell, in which ~./configure~ then runs.

After successfully running the above commands, the root directory of the GNU
Guix source tree should contain a script called ~pre-inst-env~.

[fn:snake-tail] The snake is kind of biting its own tail here, because we use an
installed ~guix~ to create a temporary environment, to run the bootstrap
script. However, since the task at hand is to add a package to an existing and
installable GNU Guix package manager, it is not necessary to worry about how the
bootstrapping behind building the package manager for the first time worked.

** Checking GNU Guix for errors
:PROPERTIES:
:CUSTOM_ID: test-package-checking-gnu-guix-for-errors
:END:

Since the GNU Guix sources have been modified, it is necessary to run tests to
check if things are still working fine. This is done by running the following
command:

#+begin_src shell
guix shell --development guix -- make check
#+end_src

Again we use the environment with all things required for GNU Guix in it. Then
we call ~make check~ inside that environment. GNU Make is already an input to
~guix~, which makes it unnecessary to write ~guix environment guix --ad-hoc make
-- make check~ instead. To use multiple CPU cores and save some time one can use
the ~-j~ argument to ~make~ as in ~make check -j8~. For example as follows:

#+begin_src shell
guix shell --development guix -- make check -j$(nproc)
#+end_src

There is no need to run ~make all~ or ~make~ here, because ~make check~ already
implies a call of ~make all~ or ~make~.

** Testing build and installation of the package
:PROPERTIES:
:CUSTOM_ID: test-package-testing-build-and-installation-of-the-package
:END:

The package has been added to the GNU Guix sources and GNU Guix has been tested
using its test suite. The next step is to test, whether the build and
installation of the added package succeed.

Again the commands used for checking build and installation will be run inside
the GNU Guix environment created by running ~guix environment guix~.

In this step the ~pre-inst-env~ script, which has been generated before, will be
used to run GNU Guix commands.

Prefix GNU Guix commands with ~./pre-inst-env~ to run them in an environment
using the local GNU Guix source tree, instead of the potentially installed GNU
Guix package manager. The idea is to make sure the environment is clean,
ensuring, that no machine specific configuration exerts an influence on the
success or failure of the build or installation of the package.

*** Testing build of the package
:PROPERTIES:
:CUSTOM_ID: test-package-testing-build-and-installation-of-the-package-testing-build-of-the-package
:END:

The instructions at [[https://guix.gnu.org/manual/en/html_node/Packaging-Guidelines.html][Packaging Guidelines]] tell to run ~./pre-inst-env guix build
guile-fslib --keep-failed~ to test package definitions. However, it is important
to note, this kind of command needs to be run inside the environment created by
~guix environment guix~!

To test the build process of the package run the following command:

#+begin_src shell
guix shell --development guix -- \
    ./LOCATION_OF_GUIX_SOURCES/pre-inst-env \
         guix build \
         --keep-failed \
         <package name>
#+end_src

For example for ~guile-fslib~ from inside the GNU Guix sources root directory
one would run the following command:

#+begin_src shell
guix shell --development guix -- \
    ./pre-inst-env \
         guix build \
         --keep-failed \
         --log-file \
         guile-fslib
#+end_src

The ~--log-file~ might need to be dropped for the command to work, if GNU Guix
complains about missing the log file.

If there are errors or the package cannot be found, the guides mention how one
can try to debug the package definition:

#+begin_quote
If the package is unknown to the guix command, it may be that the source file
contains a syntax error, or lacks a define-public clause to export the package
variable. To figure it out, you may load the module from Guile to get more
information about the actual error:

./pre-inst-env guile -c '(use-modules (gnu packages gnew))'

-- https://guix.gnu.org/manual/en/html_node/Packaging-Guidelines.html
#+end_quote

*** Testing installation of the package
:PROPERTIES:
:CUSTOM_ID: test-package-testing-build-and-installation-of-the-package-testing-installation-of-the-package
:END:

To make sure the installation is working as well, the following command is
tried:

#+begin_src shell
guix shell --development guix -- \
    ./LOCATION_OF_GUIX_SOURCES/pre-inst-env \
         guix install \
         <package name>
#+end_src

So for example for ~guile-fslib~ one would try the following command from inside
the GNU Guix sources root directory:

#+begin_src shell
guix shell --development guix -- ./pre-inst-env guix install guile-fslib
#+end_src

If this and all previous tests worked, the package definition can be send in as
a patch.

* WIP Process of creating a git patch
:PROPERTIES:
:CUSTOM_ID: process-of-creating-a-git-patch
:END:

Now, that there is a tested and hopefully functioning package definition inside
the GNU Guix sources, a git patch needs to be created. In the following the
required steps for creating a git patch according to the guidelines of the GNU
Guix project are explained.

** Creating a commit
:PROPERTIES:
:CUSTOM_ID: process-of-creating-a-git-patch-creating-a-commit
:END:

To create a patch, the changes made to need to be put into a git commit. This
commit does not have to be pushed (and probably cannot be pushed, unless
permissions to do so are available). It is sufficient to have the commit
existing locally.

The guilelines for the changelog style commit messages demand are described at
[[https://www.gnu.org/prep/standards/html_node/Change-Logs.html#Change-Logs][Change Logs]]. However, in the context of GNU Guix package manager, the guidelines
are not to be taken literally and answered one by one. Instead there are
snippets in the GNU Guix sources, located at:

+ =etc/snippets/scheme-mode=
+ =etc/snippets/text-mode=

The directory =etc/snippets/text-mode= contains the snippets for various types
of commit messages, like adding a new package or updating an existing package
and their format is the format, which is usually expected for patches, which one
sends to the Guix patches mailing list.

These are snippet definition files for =yasnippet=, an Emacs extension package,
which deals with snippet expansion. Thus one good way to create conforming
commit messages is to use Emacs, =yasnippet= and in addition to that perhaps
=magit=, to integrate with =git= or setting emacs as editor for
git[fn:set-git-editor].

[fn:set-git-editor] Such as ~git config core.editor emacs~.

** Creating a git patch file
:PROPERTIES:
:CUSTOM_ID: process-of-creating-a-git-patch-creating-a-git-patch-file
:END:

Once the commit is in place, the git patch file can be created. Patches can be
created using the following command:

#+begin_src shell
git format-patch --minimal --diff-algorithm=minimal --progress <previous commit id>
#+end_src

~<previous commit id>~ is the id of the commit before commit containing the
changes made to add the package.

** Sending the patch
:PROPERTIES:
:CUSTOM_ID: process-of-creating-a-git-patch-sending-the-patch
:END:

All that is left is sending the patch to the GNU Guix project maintainers. The
GNU Guix project has a specialized mailing list for this purpose:
=guix-patches@gnu.org=. Sending a patch to this mailing list will cause a
tracking number to be assigned to the patch, so that all future communication
regarding the patch can be grouped using that tracking number.

You have 2 options to send the patch to that e-mail address. The first option is
to copy the text of the patch and use that as message content. The second option
is to attach the patch as an attachment to the e-mail. The second option is
preferred, as it might be a more reliable process to process the attachment of
an e-mail, than it is to extract the patch from the message body of the e-mail.

For instructions on how to respond to patches using the tracking number or
sending multiple patches tracked by the same number see the official
documentation at [[https://guix.gnu.org/manual/en/html_node/Submitting-Patches.html][Submitting Patches]] and [[https://guix.gnu.org/manual/en/html_node/Submitting-Patches.html#Sending-a-Patch-Series][Sending a Patch Series]].
